package com.hxs.learn.config.shiro;

import com.google.common.collect.Maps;
import com.hxs.learn.shiro.credential.BCryptPasswordService;
import com.hxs.learn.shiro.filter.JwtOrFormAuthenticationFilter;
import com.hxs.learn.shiro.realm.MyFormRealm;
import com.hxs.learn.shiro.realm.MyJwtRealm;
import org.apache.shiro.authc.credential.PasswordMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


/**
 * @author huxinsheng
 */
@Configuration
public class ShiroConfig {
    private static Map<String, String> filterMap = new LinkedHashMap<>();

    @Bean(name = "realms")
    @Autowired
    public List<Realm> getRealms(MyJwtRealm jWTRealm, MyFormRealm formRealm) {
        List<Realm> realms = new ArrayList<>();
        realms.add(jWTRealm);
        final PasswordMatcher passwordMatcher = new PasswordMatcher();
        passwordMatcher.setPasswordService(new BCryptPasswordService());
        formRealm.setCredentialsMatcher(passwordMatcher);
        realms.add(formRealm);
        return realms;
    }

    @Bean(name = "shiroEhcacheManager")
    public EhCacheManager getEhCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
        return em;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean(name = "securityManager")
    @Autowired
    public DefaultWebSecurityManager getDefaultWebSecurityManager(List<Realm> realms) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealms(realms);
        dwsm.setCacheManager(getEhCacheManager());
        return dwsm;
    }

    @Bean
    @Autowired
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(defaultWebSecurityManager);
        return new AuthorizationAttributeSourceAdvisor();
    }

    @Bean(name = "shiroFilter")
    @Autowired
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(defaultWebSecurityManager);

        Map<String, Filter> filters= Maps.newHashMapWithExpectedSize(7);
        filters.put("jwt", new JwtOrFormAuthenticationFilter());
        shiroFilter.setFilters(filters);

        /**
         * 默认的登陆访问url
         * 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
         */
        shiroFilter.setLoginUrl("/login");
        /**
         * 登陆成功后跳转的url
         */
        shiroFilter.setSuccessUrl("/index");
        /**
         * 没有权限跳转的url
         */
        shiroFilter.setUnauthorizedUrl("/error/403");

        /**
         * 配置shiro拦截器链
         *
         * anon  不需要认证
         * authc 需要认证
         * user  验证通过或RememberMe登录的都可以
         *
         */
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterMap.put("/logout", "logout");
        // 配置不会被拦截的链接 顺序判断
        filterMap.put("/static/**", "anon");
        filterMap.put("/login", "anon");
        filterMap.put("/forget", "anon");
        filterMap.put("/core/user/resetPwd", "anon");
        filterMap.put("/druid/**", "anon");
        filterMap.put("/error/**", "anon");
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/v2/**", "anon");
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/captcha", "anon");
        filterMap.put("/core/socket", "anon");
        filterMap.put("/favicon.ico", "anon");
        filterMap.put("/core/res/**", "anon");
        filterMap.put("/index", "user");
        filterMap.put("/", "user");
        // <!-- 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterMap.put("/**", "jwt");
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }
}
